/*
 * Copyright:  2018 smarabbit studio.
 *
 *  Licensed under the Confluent Community License; you may not use this file
 *  except in compliance with the License.  You may obtain a copy of the License at
 *
 *  http://www.confluent.io/confluent-community-license
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations under the License.
 *
 *  @作   者： 黄开晖 (117227773@qq.com)
 *  @日   期:  2021年8月17日
 */
package com.massyframework.beanskin.maven.plugin;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.PluginExecution;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.codehaus.plexus.util.xml.Xpp3Dom;

/**
 * @author huangkh
 *
 */
public abstract class ArtifactsMojo extends AbstractMojo {

	private static final String ARTIFACT_ITEM         = "artifactItem";
	private static final String GROUPID               = "groupId";
	private static final String ARTIFACTID            = "artifactId";
	private static final String VERSION               = "version";
	
	@Parameter(defaultValue="${localRepository}", readonly = true, required = true)
    private ArtifactRepository artifactRepository;
	
	/**
	 * 
	 */
	public ArtifactsMojo() {
		
	}

	/**
	 * 定位Jar文件
	 * @param artifacts {@link Artifact}
	 * @return {@link List}
	 */
	protected List<File> locateJars(List<Artifact> artifacts){
		List<File> result = new ArrayList<File>();
		
		for (Artifact artifact: artifacts) {
			File file = this.locateJarFile(artifact);
			if (file != null) {
				result.add(file);
			}
		}
		return result;
	}
	
	/**
	 * 定位{@code artifact}的jar文件
	 * @param artifact {@link Artifact}
	 * @return {@link File},可能返回null.
	 */
	protected File locateJarFile(Artifact artifact) {
		Artifact a = this.artifactRepository.find(artifact);
		if (a != null) {
			String path = a.getFile().getPath().concat(".jar");
			File file = new File(path);
			if (file.exists()) {
				return file;
			}else {
				this.getLog().error("cannot found " + artifact  + " file:" + path + ".");
				return null;
			}
		}
		
		this.getLog().error("cannot found " + artifact  + ".");
		return null;
	}
	
	/**
	 * 从插件中加载需要整合的工件
	 * @param plugin {@link Plugin}，插件
	 * @param goal {@link String},目标
	 * @return {@link List}
	 */
	protected List<Artifact> loadArtifactItems(Plugin plugin, String goal){
		if (plugin == null) return Collections.emptyList();
		
		Xpp3Dom configuration = this.getConfiguration(plugin, goal);
		return this.loadArtifactItems(configuration);
	}
	
	/**
	 * 从插件中提取指定{@code goal}的配置
	 * @param plugin {@link Plugin}
	 * @param goal {@link String},目标
	 * @return {@link Xpp3Dom}
	 */
	protected Xpp3Dom getConfiguration(Plugin plugin, String goal) {
		if (plugin == null) return null;
		PluginExecution execution = this.findPluginExecution(plugin, goal);
		if (execution != null) {
			Object configuration = execution.getConfiguration();
			if (configuration != null) {
				if (configuration instanceof Xpp3Dom) {
					return (Xpp3Dom)configuration;
				}
			}
		}
			
		return null;
	}
	
	/**
	 * 从{@code configuration}中解析所需工件
	 * @param configuration {@link Xpp3Dom}
	 * @return {@link List}
	 */
	protected List<Artifact> loadArtifactItems(Xpp3Dom configuration){
		if (configuration == null) return Collections.emptyList();
		List<Artifact> result = new ArrayList<>();
		Xpp3Dom childs = configuration.getChild("artifactItems");
		for (int i=0; i<childs.getChildCount(); i++) {
			Xpp3Dom item = childs.getChild(i);
			Artifact artifact = this.loadArtifact(item, this.createArtifactBuilder()) ;
			if (artifact != null) {
				result.add(artifact);
			}
		}
		return result;
	}

	/**
	 * 查找执行器
	 * @param plugin {@link Plugin},插件
	 * @param goal {@link String},目标
	 * @return {@link PluginExecution}
	 */
	protected PluginExecution findPluginExecution(Plugin plugin, String goal) {
    	if (plugin == null) return null;
    	
    	return plugin.getExecutions().stream()
    			.filter( execution -> execution.getGoals().contains(goal))
    			.findFirst()
    			.orElse(null);
    }
	
	/**
	 * 加载工件
	 * @param item {@link Xpp3Dom}
	 * @param builder {@link ArtifactBuilder}
	 * @return {@link Artifact}
	 */
	private Artifact loadArtifact(Xpp3Dom item, ArtifactBuilder builder) {
		try {
	    	if (ARTIFACT_ITEM.equals(item.getName())) {
	    		String groupId = item.getChild(GROUPID).getValue();
		    	String artifactId = item.getChild(ARTIFACTID).getValue();
		    	String version = item.getChild(VERSION).getValue();
		    	
		    	builder.groupId(groupId)
		    		.artifactId(artifactId)
		    		.version(version);
		    	this.customArtifactBuilder(item, builder);
		    	
		    	return builder.build();
	    	}
    	}catch(Exception e) {
    		this.getLog().error(e.getMessage(), e);
    	}
		
    	return null;
	}
	
	protected void customArtifactBuilder(Xpp3Dom item, ArtifactBuilder builder) {
		
	}
	
	
	/**
	 * 创建工件构建器
	 * @return {@link ArtifactBuilder}
	 */
	protected abstract ArtifactBuilder createArtifactBuilder();
}
